import {
  Invitation,
  Inviter,
  Referral,
  Registerer,
  RegistererOptions,
  Session,
  SessionState,
  UserAgent,
  UserAgentOptions,
  UserAgentDelegate,
  Core,
  Web,
  RegistererRegisterOptions,
  InvitationAcceptOptions
} from 'sip.js'

// import md5 from 'md5'
interface Options {
  server: string,
  sip: string,
  secret: string,
  onmessage?(event: string): void
  error?(error: string): void
}
// let registerer: any = {}
// let currentConfig: any = {}
// let Ginvitation: Invitation
export default class M7Webrtc {
  private config: Options | undefined
  private registerer
  private userAgent
  public message: ((any) => void | undefined) | undefined
  private Ginvitation: Invitation | undefined
  constructor (options) {
    this.init(options)
  }

  private init (config: Options) {
    // 获取HTMLElement
    this.config = config
    const audioElement = getAudio('m7remoteAudio')
    // HTMLElement to 获取HTMLElement
    function getAudio (id: string): HTMLAudioElement {
      const el = document.getElementById(id)
      if (!(el instanceof HTMLAudioElement)) { // 没有音频dom,重新创建一个
        // throw new Error(`Element '${id}' not found or not an audio element.`)
        const audio = new Audio()
        audio.controls = true
        audio.autoplay = true
        audio.id = 'm7remoteAudio'
        audio.style.display = 'none'
        document.body.appendChild(audio)
        return document.getElementById(id) as HTMLAudioElement
      } else {
        return el
      }
    }
    // Assign a MediaStream to an HTMLMediaElement and update if tracks change.
    // 媒体流绑定标签
    function assignStream (stream: MediaStream, element: HTMLMediaElement): void {
      // Set element source.
      element.autoplay = true; // Safari does not allow calling .play() from a non user action
      element.srcObject = stream;

      // Load and start playback of media.
      element.play().catch((error: Error) => {
        console.error('Failed to play media');
        console.error(error);
      });

      // If a track is added, load and restart playback of media.
      stream.onaddtrack = (): void => {
        element.load(); // Safari does not work otheriwse
        element.play().catch((error: Error) => {
          console.error('Failed to play remote media on add track');
          console.error(error);
        });
      };

      // If a track is removed, load and restart playback of media.
      stream.onremovetrack = (): void => {
        element.load(); // Safari does not work otheriwse
        element.play().catch((error: Error) => {
          console.error('Failed to play remote media on remove track');
          console.error(error);
        });
      };
    }
    /*
     * Create a user agent
     * 创建用户代理
     */
    const transportOptions = {
      server: 'wss://' + config.server
    }

    const userAgentDelegate: UserAgentDelegate = {
      onInvite: (invitation: Invitation): void => {
        console.log('userAgent invitation', invitation)
        this.Ginvitation = invitation
        // An Invitation is a Session
        const incomingSession: Session = invitation
        // Setup incoming session delegate
        incomingSession.delegate = {
          // Handle incoming REFER request.
          onRefer (referral: Referral): void {
            console.log(referral)
          }
        };
        this.sendMessage('incomingcall')
        this.Ginvitation._onCancel = (message): void => {
          this.sendMessage('cancel')
        }
        // Handle incoming session state changes.
        incomingSession.stateChange.addListener((state: SessionState) => {
          switch (state) {
            case SessionState.Initial:
              break;
            // 会话建立
            case SessionState.Establishing:
              break;
            // 会话已经建立
            case SessionState.Established:
              // eslint-disable-next-line no-case-declarations
              const sessionDescriptionHandler = incomingSession.sessionDescriptionHandler
              if (!sessionDescriptionHandler || !(sessionDescriptionHandler instanceof Web.SessionDescriptionHandler)) {
                throw new Error('Invalid session description handler.');
              }
              if (audioElement) {
                assignStream(sessionDescriptionHandler.remoteMediaStream, audioElement)
              }
              break;
            case SessionState.Terminating:
              break;
            case SessionState.Terminated:
              break;
            default:
              throw new Error('Unknown session state.');
          }
        })
      }
    }

    const uri = UserAgent.makeURI('sip:' + config.sip + '@' + config.server);
    if (!uri) {
      throw new Error('Failed to create URI');
    }
    const userAgentOptions: UserAgentOptions = {
      delegate: userAgentDelegate,
      displayName: '7moor',
      uri,
      transportOptions,
      authorizationUsername: config.sip,
      authorizationPassword: config.secret
      /* ... */
    };
    this.userAgent = new UserAgent(userAgentOptions);
    const registererOptions: RegistererOptions = {
      expires: 10
    }
    this.registerer = new Registerer(this.userAgent, registererOptions);

    /***
     * 注册的状态
     */
    const requestDelegate: Core.OutgoingRequestDelegate = {
      onAccept: (response: Core.IncomingResponse): void => {
        console.log('onAccept.....', response)
      },
      onProgress: (response: Core.IncomingResponse): void => {
        console.log('onProgress.....', response)
      },
      onRedirect: (response: Core.IncomingResponse): void => {
        console.log('onRedirect.....', response)
      },
      onReject: (response: Core.IncomingResponse): void => {
        console.log('onReject.....', response)
      },
      onTrying: (response: Core.IncomingResponse): void => {
        console.log('onTrying.....', response)
      }
    }

    const registererRegisterOptions: RegistererRegisterOptions = {
      requestDelegate
    }
    this.registerHandle(registererRegisterOptions)
  }

  private async registerHandle (registererRegisterOptions: RegistererRegisterOptions) {
    await this.userAgent.start();
    // 注册
    await this.registerer.register(registererRegisterOptions);
  }

  public accept = async (): Promise<void> => {
    const constrainsDefault: MediaStreamConstraints = {
      audio: true,
      video: false
    }
    const options: InvitationAcceptOptions = {
      sessionDescriptionHandlerOptions: {
        constraints: constrainsDefault
      }
    }
    return (this.Ginvitation as Invitation).accept(options)
  }

  public m7UnregisterWebrtc = async (): Promise<boolean | void> => { // 取消注册
    if (!this.registerer) {
      return false
    }
    return this.registerer.unregister({ all: true }).then((res) => {
      console.log(res, '注销webrtc成功=======')
    }).catch((e) => {
      console.log(e, '注销webrtc失败=======')
    })
  }

  private sendMessage (message: string) {
    if (this.message) {
      this.message(message)
    }
  }
}
